/*—————————————————————————————————————————————————————————— form封装组件 ——————————————————————————————————————————————————————————*/

/*

*传入参数
 因参数过多故请参考 本文件夹中 interface 文件，或等后续提供相关的项目文档网址

*交互方法
   因参数过多故请参考 本文件夹中 interface 文件，或等后续提供相关的项目文档网址

***用法介绍***
  此处只介绍基础用法，因此组件比较复杂，故详细用法可以等后续的项目文档开发后，进行线上参考
  1.推荐使用 formitemlist 传参的形式进行渲染使用此form组件，若是需要配合设置默认值可以使用 formitemvalue 属性进行配套动态改变
    示例:
      <Form
        requiredMark={false}
        formitemlist={[
          {
            type: 'input',
            name: 'input',
            label: 'input',
          },
        ]}
        formitemvalue={{
          input: 32,
        }}
      />

  2.如果需要设置默认值的同时，且还需要在每次重置后，恢复默认值，则可以在传入的 formitemlist 成员中添加 initialValue 参数即可
    示例：
      <Form
        requiredMark={false}
        formitemlist={[
          {
            type: 'input',
            name: 'input',
            label: 'input',
            initialValue:'重置默认值'
          },
        ]}
      />

  3.我们开发时，若是需要在成员属性自定义中得到ts的代码提示，可先定义好传入的数组类型，使用泛型的形式传入需要提示的组件信息
    示例:
      type Forms = [
       formItems<'input'>,
      ]

      const forms: Forms =[
        {
            type: 'input',
            name: 'input',
            label: 'input',
            itemconfig: {
              maxLength: 3,
              showCount: true,
              placeholder: '请输入',
            },
        }
      ]
*/
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// 数据+css引入
import React, {
  forwardRef,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
} from 'react'
import './form.scss'

// 公共方法
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
import { formSupportItem, valuePropNameMap } from './toolkit'

// ts接口
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
import type { FormsProps, FormRef, formItems } from './interface'

// 组件引入
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
import { Col, Form, Row, Button } from 'antd'
import { HappyProvider } from '@ant-design/happy-work-theme'

// 页面书写区
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
const Forms = forwardRef(
  (props: FormsProps, ref: React.ForwardedRef<FormRef>) => {
    // 参数结构
    const {
      slotTop, // 上方插入内容
      slotDown, // 下方插入内容
      showFoundationBtn = true, // 是否展示基础按键部分,默认true
      formSize = 'large', // 表单展示大小,默认large
      formitemlist = [], // 表单渲染成员列表,默认空数组
      formitemvalue = {}, // 表单成员动态值内容
      row, // 整体排列属性配置

      // 方法区域
      // -----------------------------------------------------------------------------------------------------------
      onFieldsChange, // 字段更新时触发回调事件
      onFinish, // 提交表单且数据验证成功后回调事件
      onFinishFailed, // 提交表单且数据验证失败后回调事件
      onValuesChange, // 字段值更新时触发回调事件

      // 剩余参数打散集合
      ...rest
    } = props

    // 变量声明区
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // ref声明
    const formItemKeys = useRef<Array<string>>([]) // 当前form动态值的keys

    // 状态声明
    // -----------------------------------------------------------------------------------------------------------
    const [form] = Form.useForm() // 当前form的实例

    // 函数使用区
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // memo数据

    // form表单子集成员dom生成属性树
    const formItem = useMemo(
      () =>
        formitemlist.map((val, ind) => {
          //  当前循环中form表单应该展示的组件
          const FormItem: React.ElementType = formSupportItem[val.type]

          // 若是首次执行时，获取不到form元素还未创建，故需要在异步中进行获取内容
          // =========================================================================================
          setTimeout(() => {
            // 根据当前的name属性进行判断是否在此时的form实例上有了属性，没得就在 fieldsValue 中赋予默认值
            form.getFieldValue(val.name) ??
              // 如果此时是设置了默认重置值的，那么赋予此默认重置值，否则为undefined
              form.setFieldValue(
                val.name,
                val.initialValue ? val.initialValue : undefined
              )
          })

          // 弹出此时dom化后的内容
          // =========================================================================================
          return (
            <Col span={24} {...val.col} key={ind}>
              <Form.Item
                colon={false}
                {...val}
                valuePropName={valuePropNameMap[val.type]}
              >
                {/* 需要渲染的form表单类型 */}
                <FormItem {...val.itemconfig} />
              </Form.Item>
              {/* 额外的dom节点 */}
              {val.extraRendering}
            </Col>
          )
        }),
      [JSON.stringify(formitemlist)]
    )

    // hook函数
    // -----------------------------------------------------------------------------------------------------------
    // 监听 formitemvalue表单成员动态值内容 的变化
    useEffect(() => {
      // 获取当前动态值的keys
      formItemKeys.current = Object.keys(formitemvalue)

      // 如果有成员的情况下
      if (formItemKeys.current.length) {
        // 深克隆此时的值
        const formValue = JSON.parse(JSON.stringify(formitemvalue))

        // 赋予当前的表单内容
        form.setFieldsValue(formValue)
      }
    }, [JSON.stringify(formitemvalue)])

    // 事件函数
    // -----------------------------------------------------------------------------------------------------------

    // 表单重置方法
    const formReset = () => {
      form.resetFields(Object.keys(form.getFieldsValue(true)))
    }

    // 暴露给父组件的方法
    // -----------------------------------------------------------------------------------------------------------
    useImperativeHandle(ref, () => ({
      form, // 导出当前的form实例
      formValues: form.getFieldsValue(true), // 此时表单的内容

      // 方法区域
      // =========================================================================================
      formReset, // 表单重置方法
    }))

    // dom元素区域
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    return (
      <Form
        size={formSize}
        labelCol={{ span: 2 }}
        {...rest}
        form={form}
        onFieldsChange={onFieldsChange && onFieldsChange}
        onFinish={onFinish && onFinish}
        onFinishFailed={onFinishFailed && onFinishFailed}
        onValuesChange={onValuesChange && onValuesChange}
      >
        {/* 表单展示区域 */}
        <Row justify="center" className="forms pr" gutter={[24, 12]} {...row}>
          {/* 基础按键 */}
          {/* ========================================================================================= */}
          {showFoundationBtn && (
            <Col span={24} className="formsBtnBox ps">
              <Row justify="end">
                <HappyProvider>
                  <Button type="primary" htmlType="submit" size="middle">
                    提 交
                  </Button>

                  <Button
                    type="primary"
                    htmlType="button"
                    ghost
                    className="formBtn"
                    size="middle"
                    onClick={formReset}
                  >
                    重 置
                  </Button>

                  <Button className="formBtn" size="middle">
                    取 消
                  </Button>
                </HappyProvider>
              </Row>
            </Col>
          )}

          {/* 上方插槽插入 */}
          {/* ========================================================================================= */}
          {slotTop}

          {/* 成员组合 */}
          {/* ========================================================================================= */}
          {formItem}

          {/* 下方插槽插入 */}
          {/* ========================================================================================= */}
          {slotDown}
        </Row>
      </Form>
    )
  }
)

export type { FormsProps, FormRef, formItems }

export default Forms
